import sys
import json
import base64
from io import BytesIO
from jsonpath_ng import jsonpath, parse
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import QTimer
import paho.mqtt.client as mqtt
from PIL import Image, ImageQt
from PyQt5.QtGui import QPixmap, QImage


client_id = f"picture_dev|securemode=2,signmethod=hmacsha1,timestamp=1719988347237|"
# timestamp = str(int(time.time()))
username = f"picture_dev&k17qfYOFMoU"
password = f"E9999FED029C98481E0ACC58CD7F1078793DF2C5"

broker = f"k17qfYOFMoU.iot-as-mqtt.cn-shanghai.aliyuncs.com"

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()
        self.connect_mqtt()

    def initUI(self):
        self.setWindowTitle('MQTT Image Receiver')
        self.setGeometry(100, 100, 800, 600)
        self.label = QLabel(self)
        self.label.setGeometry(10, 10, 780, 580)  # 留出一些边距

    def connect_mqtt(self):
        self.mqtt_client = mqtt.Client(client_id=client_id)
        self.mqtt_client.on_connect = self.on_connect
        self.mqtt_client.on_message = self.on_message
        self.mqtt_client.username_pw_set(username, password)
        # 连接到 MQTT 服务器（替换为你的 MQTT 服务器地址和端口）
        self.mqtt_client.connect(broker, 1883, 60)

        # 使用 QTimer 周期性地调用 mqtt_client.loop_start()
        # 注意：这通常不是最佳实践，因为 loop_start() 应该只调用一次
        # 但为了简单起见，并且假设你不需要在 GUI 线程中做太多其他事情，这里这样做
        self.mqtt_timer = QTimer(self)
        self.mqtt_timer.timeout.connect(self.mqtt_client_loop)
        self.mqtt_timer.start(1000)  # 每秒调用一次

    def mqtt_client_loop(self):
        # 注意：这通常不是处理 MQTT 循环的正确方式
        # 但由于 PyQt5 的事件循环和 MQTT 的网络事件循环需要分开，这里作为示例
        # 在实际应用中，你可能需要更复杂的集成或使用其他库（如 asyncio）
        self.mqtt_client.loop_start()
        # 注意：由于 loop_start() 会阻塞直到连接关闭，所以我们实际上不会在这里停留
        # 但由于我们每秒都调用它，并且 MQTT 客户端是智能的，它会在已经运行时忽略重复的 loop_start()

    def pil_image_to_qpixmap(self,image):
        """将PIL图像转换为QPixmap"""
        # 注意：ImageQt.Image 实际上是一个 QImage 的子类，但通常我们不会直接使用它
        # 相反，我们会通过PIL图像来创建一个QImage对象
        q_img = QImage(image.tobytes("raw", "RGB"),
                       image.size[0], image.size[1],
                       QImage.Format_RGB888).rgbSwapped()
        pixmap = QPixmap.fromImage(q_img)
        return pixmap

    def on_connect(self, client, userdata, flags, rc):
        print(f"Connected with result code {str(rc)}")
        # 订阅 MQTT 主题（替换为你的主题）
        client.subscribe("/k17qfYOFMoU/picture_dev/user/get")

    def on_message(self, client, userdata, msg):

        # 假设 msg.payload 是一个包含 JSON 数据的字节串
        json_str = msg.payload.decode('utf-8')
        json_data = json.loads(json_str)  # 将 JSON 字符串解码为 Python 字典

        # 定义 JSONPath 表达式来查询图片数据的 Base64 编码
        # 假设图片数据在 JSON 对象的 "image" 键下，并且 Base64 编码存储在 "base64" 键下
        jsonpath_expr = parse('$.params.image')

        # 使用 JSONPath 查找匹配项
        matches = jsonpath_expr.find(json_data)

        if matches:
            # 假设我们总是只处理第一个匹配项（如果有多个，你可能需要遍历它们）
            base64_str = matches[0].value
            image_bytes = base64.b64decode(base64_str)

            # 使用 PIL 加载图片并显示在 GUI 中
            image = Image.open(BytesIO(image_bytes))
            pixmap = self.pil_image_to_qpixmap(image)
            self.label.setPixmap(pixmap)
            self.label.resize(pixmap.size())
        else:
            print("No image data found in the JSON message.")


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = MainWindow()
    ex.show()
    # 注意：通常不需要在 PyQt5 应用程序中显式调用 mqtt_client.loop_forever()
    # 因为 PyQt5 的事件循环会处理 GUI 更新和 MQTT 消息（如果你正确地集成了 MQTT 客户端）
    # 但由于上面的 mqtt_client_loop() 方法不是最佳实践，这里仅作为示例
    sys.exit(app.exec_())

# 注意：上面的 mqtt_client_loop() 方法并不是处理 MQTT 消息的最佳方式
# 在实际应用中，你可能需要更复杂的集成，比如使用 QThread 来运行 MQTT 客户端的网络循环
# 或者使用支持异步操作的 MQTT 客户端库（如 paho-mqtt 的异步版本）